package reading.common;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.slf4j.LoggerFactory;
import reading.common.constant.NumStringConstant;
import reading.common.constant.SpecialStringConstant;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author Gang Zou on 16-12-1.
 * @author Gang Zou
 * @date 16-12-01
 */
public class CommonUtil {
    private final static String FIREFOX = "Firefox";
    private final static String CHROME = "Chrome";
    private final static String REG_EX = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
    /**
     * 5点结束任务
     */
    private final static int HOUR = 5;
    private final static Pattern NUMBER_REX = Pattern.compile("[0-9]");
    private final static Pattern NUMBER_PATTERN = Pattern.compile("[0-9]*");
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(CommonUtil.class);
    private static Pattern pattern = Pattern.compile(REG_EX);
    private static java.text.DecimalFormat df = new java.text.DecimalFormat("#.00");

    public static String filterSpecailStr(String str) {
        Matcher m = pattern.matcher(str);
        return m.replaceAll("");
    }

    public static boolean isNotNullAndNumber(String str) {
        return isNotNull(str) && isNumeric(str);
    }

    /**
     * 是否数字
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        Matcher isNum = NUMBER_PATTERN.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    public static String stringDatePattern(String date, String resourcePattern, String targetPattern) {
        if (isNullAndNullStr(date)) {
            return "";
        } else {
            return parseDate(checkDate(date, resourcePattern), targetPattern);
        }
    }

    public static Date checkDate(String date, String pattern) {
        Date e = new Date();
        try {
            e = getInstance(pattern).parse(date);
        } catch (ParseException e1) {
            e1.printStackTrace();
        }
        return e;
    }

    public static SimpleDateFormat getInstance(String type) { ///得到实例并分配空间
        return new SimpleDateFormat(type);
    }

    public static String format(Date date) {
        return getInstance("yyyy-MM-dd HH:mm:ss").format(date);
    }

    public static String getNow() {
        return format(new Date());
    }

    public static boolean isNull(String str) {
        return str == null || str.trim().length() == 0;
    }

    public static boolean isNotNull(String str) {
        return !(str == null || str.trim().length() == 0);
    }

    public static String getNowYMD() {
        Calendar c = Calendar.getInstance();
        String s = "";
        s += c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月" + c.get(Calendar.DATE) + "日";
        return s;
    }

    public static boolean isNullAndNullStr(String str) {
        return str == null || str.trim().length() == 0 || "null".equals(str.trim().toLowerCase());
    }

    public static boolean isLetterOrNumberAndLength(String str, int len) {
        return isLetterOrNumber(str) && str.length() == len;
    }

    public static String parseDate(Date date, String pattern) {
        return getInstance(pattern).format(date);
    }

    public static String html2text(String html) {
        return Jsoup.parse(html).text();
    }

    /**
     * 全角转半角
     *
     * @param input String.
     * @return 半角字符串
     */
    public static String toDBC(String input) {
        char[] c = input.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] == '\u3000') {
                c[i] = ' ';
            } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
                c[i] = (char) (c[i] - 65248);
            }
        }
        return new String(c);
    }

    /**
     * 脱敏身份证
     *
     * @param str
     * @return
     */
    public static String vagueString(String str) {
        if (str == null) {
            return str;
        }
        char[] c = str.toCharArray();
        /**
         * 身份证隐藏中间6位（身份证分为前6位中间6位后6位，总共18位）
         * 2017-07-15日发改委演示提出的要求
         */
        for (int i = 0; i < c.length; i++) {
            c[i] = '*';
        }
        return String.valueOf(c);
    }

    public static String trimSpace(String str) throws UnsupportedEncodingException {
        String s = str.trim();
        s = s.replaceAll(" ", "");
        s = s.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
        s = s.replaceAll("\\+", "%2B");
        s = URLDecoder.decode(s, "utf-8");
        return toDBC(s);
    }

    /**
     * 下划线转驼峰
     *
     * @param param
     * @return
     */
    public static String underlineToCamel(String param) {
        if (StringUtils.isBlank(param)) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == '_') {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static boolean isLetterOrNumber(String str) {
        return str.matches("^[0-9a-zA-Z]+$");
    }

    public static int getMapValueSize(Map<String, Object> map) {
        if (map.isEmpty()) {
            return 0;
        }
        int n = 0;
        for (Object obj : map.values()) {
            if (obj != null) {
                n++;
            }
        }
        return n;
    }

    public static String concatSqlInsertColumns(List<String> colmunsName) {
        return colmunsName.stream().filter(StringUtils::isNotEmpty).collect(Collectors.joining(","));
    }

    /**
     * 是否继续任务
     *
     * @return
     */
    public static boolean isTask() {
        Calendar calendar = Calendar.getInstance();
        int i = calendar.get(Calendar.HOUR_OF_DAY);
        return i != HOUR;
    }

    public static String format(Timestamp timestamp) {
        /**
         * DateFormats是非线程安全的
         * 每次调用创建新的对象
         */
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
    }

    public static boolean stringContainsNumber(String s) {

        Matcher m = NUMBER_REX.matcher(s);
        return m.find();
    }

    /**
     * 对文件流输出下载的中文文件名进行编码 屏蔽各种浏览器版本的差异性
     *
     * @throws UnsupportedEncodingException
     */
    public static String encodeChineseDownloadFileName(
            HttpServletRequest request, String pFileName) throws UnsupportedEncodingException {

        String filename;
        String agent = request.getHeader("USER-AGENT");
        if (null != agent) {
            /**
             * Firefox
             */
            if (agent.contains(FIREFOX)) {
                filename = "=?UTF-8?B?" + (new String(org.apache.commons.codec.binary.Base64.encodeBase64(pFileName.getBytes("UTF-8")))) + "?=";
                /**
                 * Chrome
                 */
            } else if (agent.contains(CHROME)) {
                filename = new String(pFileName.getBytes(), "ISO8859-1");
            } else {//IE7+
                filename = java.net.URLEncoder.encode(pFileName, "UTF-8");
                /**
                 * 替换空格
                 */
                filename = StringUtils.replace(filename, "+", "%20");
            }
        } else {
            filename = pFileName;
        }
        return filename;
    }

    public static String formatDouble(float d) {
        if (d == 0) {
            return "0";
        }
        String s = df.format(d);
        return cutFloatStr(s);
    }

    public static String cutFloatStr(String s) {
        if (s.lastIndexOf(NumStringConstant.ZERO) == s.length() - 1) {
            return cutFloatStr(s.substring(0, s.lastIndexOf(NumStringConstant.ZERO)));
        } else {
            if (s.lastIndexOf(SpecialStringConstant.DOT) == s.length() - 1) {
                return (s.substring(0, s.lastIndexOf(SpecialStringConstant.DOT)));
            } else {
                return s;
            }

        }
    }

    /**
     * 将一个 JavaBean 对象转化为一个 Map
     * <一句话功能简述>
     * <功能详细描述>
     *
     * @param bean
     * @return
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @see [类、类#方法、类#成员]
     */
    public static Map<String, Object> convertBean2Map(Object bean)
            throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        Class<? extends Object> type = bean.getClass();
        Map<String, Object> returnMap = new HashMap<>(16);
        BeanInfo beanInfo = Introspector.getBeanInfo(type);

        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (!"class".equals(propertyName)) {
                Method readMethod = descriptor.getReadMethod();
                Object result = readMethod.invoke(bean, new Object[0]);
                if (result != null) {
                    returnMap.put(propertyName, result);
                } else {
                    returnMap.put(propertyName, null);
                }
            }
        }
        return returnMap;
    }


    /**
     * 优化split
     *
     * @param s
     * @param reg
     * @return
     */
    public static List<String> split(String s, String reg) {
        if (isNull(s)) {
            return null;
        }
        String temp = s;
        List<String> strings = new ArrayList<>();
        for (int i = 0, len = s.length(); i < len; i++) {
            while (true) {
                String splitStr = null;
                int j = temp.indexOf(reg);
                if (j < 0) {
                    break;
                }
                splitStr = temp.substring(0, j);
                strings.add(splitStr);
                temp = temp.substring(j + 1);
            }
        }
        return strings;
    }

    /**
     * 优化split
     *
     * @param s
     * @param reg
     * @return
     */
    public static List<String> splits(String s, String reg) {
        if (isNull(s)) {
            return null;
        }
        StringTokenizer st = new StringTokenizer(s, reg);
        List<String> strings = new ArrayList<>();
        while (st.hasMoreTokens()) {
            strings.add(st.nextToken());
        }
        return strings;
    }

}
